﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LanguagePolish.Base
{
    public abstract class BaseViewModelErrorInfo : BaseViewModel, IDataErrorInfo
    {
        private class Binder
        {
            private class RuleMessage
            {
                public Func<bool> Rule { get; set; }
                public string Message { get; set; }
            }

            public string Error { get; private set; }

            public bool HasError { get; private set; }

            private List<RuleMessage> Rules { get; set; }

            public Binder()
            {
                Rules = new List<RuleMessage>();
            }

            public void Add(Func<bool> ruleDelegate, string errorMessage)
            {
                Rules.Add(new RuleMessage { Rule = ruleDelegate, Message = errorMessage });
            }

            public void Update()
            {
                Error = string.Empty;
                HasError = false;
                List<string> errors = new List<string>();
                foreach (var rule in Rules)
                {
                    if (rule.Rule())
                        errors.Add(rule.Message);
                }
                if (errors.Count > 0)
                {
                    HasError = true;
                    Error = string.Join("\n", errors);
                }
            }
        }
        
        private readonly Dictionary<string, Binder> rules = new Dictionary<string, Binder>();

        public bool HasErrors
        {
            get
            {
                foreach (var rule in rules)
                {
                    rule.Value.Update();
                    if (rule.Value.HasError)
                        return true;
                }
                return false;
            }
        }

        protected BaseViewModelErrorInfo()
        {
            CreateRules();
        }

        protected void AddRule(string propertyName, Func<bool> ruleDelegate, string errorMessage)
        {
            Binder binder;
            if (rules.TryGetValue(propertyName, out binder))
            {
                binder.Add(ruleDelegate, errorMessage);
            }
            else
            {
                binder = new Binder();
                binder.Add(ruleDelegate, errorMessage);
                rules.Add(propertyName, binder);
            }
        }

        public virtual void CreateRules()
        {
        }

        public string Error
        {
            get { return null; }
        }

        public string this[string columnName]
        {
            get
            {
                Binder binder;
                if (!rules.TryGetValue(columnName, out binder))
                    return null;
                binder.Update();
                return binder.Error;
            }
        }
    }
    
}
